iT邦幫忙

2022 iThome 鐵人賽

DAY 16
0
Software Development

SQL rookie 之天天魯一下系列 第 16

Day 16 - CollectionProxy 是什麼咧?(2)

  • 分享至 

  • xImage
  •  

Hi, 大家好!

繼昨天的研究,我們目前知道CollectionProxy 涉及到三個objects:owner、target、Reflection

以上篇的例子來看:

irb(main):006:0> User.first.posts.class
  User Load (3.2ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT $1  [["LIMIT", 1]]
Post::ActiveRecord_Associations_CollectionProxy < ActiveRecord::Associations::CollectionProxy

owner 為User.first、target 為posts,那Reflection object 呢?

我們先來看看在Rails API 搜尋Reflection 可以得到的結果:
Reflection on Rails API

從圖裡可看到Reflection 是ActiveRecord 下的一個類別:

Reflection enables the ability to examine the associations and aggregations of Active Record classes and objects. This information, for example, can be used in a form builder that takes an Active Record object and creates input fields for all of the attributes depending on their type and displays the associations to other objects.

**翻譯蒟蒻:Reflection 具有可檢視associations/aggregations 裡物件的能力。而檢視到的資訊可透過form builder 來建立目標的attributes。

猜測這應該解釋了我們為什麼可以這麼建立資料吧:

irb(main):017:0> User.first.posts.create(title: "IThome", body: "IThome rocks")
  User Load (0.8ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT $1  [["LIMIT", 1]]
   (0.2ms)  BEGIN
  User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
  Post Create (8.0ms)  INSERT INTO "posts" ("userId", "title", "body", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id"  [["userId", 1], ["title", "IThome"], ["body", "IThome rocks"], ["created_at", "2022-10-01 13:20:49.585730"], ["updated_at", "2022-10-01 13:20:49.585730"]]
   (2.6ms)  COMMIT
#<Post:0x00007fb4a8338a38> {
            :id => 101,
        :userId => 1,
         :title => "IThome",
          :body => "IThome rocks",
    :created_at => Sat, 01 Oct 2022 13:20:49 UTC +00:00,
    :updated_at => Sat, 01 Oct 2022 13:20:49 UTC +00:00
}

Reflectin Class的第二句說明:

MacroReflection class has info for AggregateReflection and AssociationReflection classes.

**翻譯蒟蒻:MacroReflection 有associations/aggregations 的資訊

可看到這邊還是有點不懂,那MacroReflection 是什麼呢:

ActiveRecord::Reflection::MacroReflection < ActiveRecord::Reflection::AbstractReflection
activerecord/lib/active_record/reflection.rb

Base class for AggregateReflection and AssociationReflection. Objects of AggregateReflection and AssociationReflection are returned by the Reflection::ClassMethods.

**翻譯蒟蒻:結合了這兩個類別的說明,應該是指Reflection 下有個MacroReflection,當使用Reflection 的類別方法時會回傳MacroReflection,上面有associations/aggregations 的資訊

而先看看ActiveRecord::Reflection::MacroReflection 的方法

MacroReflection attributes and new method
大概能理解我們可以這樣做:

ActiveRecord::Reflection::MacroReflection.new(:user, { id: 1 }, ...... }

# 好吧,後面我還不知道怎麼做 XD 但我們能從下方的實體方法來一窺一二

irb(main):008:0> User.reflect_on_association(:posts)
#<ActiveRecord::Reflection::HasManyReflection:0x00007fb4a32dfca8 @name=:posts, @scope=nil, @options={:foreign_key=>:userId}, @active_record=User(id: integer, created_at: datetime, updated_at: datetime, name: string, username: string, email: text, phone: text, website: text), @klass=Post(id: integer, userId: integer, title: text, body: text, created_at: datetime, updated_at: datetime), @plural_name="posts", @type=nil, @foreign_type=nil, @constructable=true, @inverse_name=nil, @class_name="Post", @foreign_key=:userId, @active_record_primary_key="id", @inverse_which_updates_counter_cache=nil>

讓我們先跳去看看Reflection 的類別方法

.macro -> 可得知彼此(User vs Post)的關聯方法

irb(main):020:0> User.reflect_on_association(:posts).macro
:has_many

.reflect_on_all_associations -> 回傳User 和其他Model 的Reflection

irb(main):021:0> User.reflect_on_all_associations
[
    [0] #<ActiveRecord::Reflection::HasManyReflection:0x00007fb4a32dfca8 @name=:posts, @scope=nil, @options={:foreign_key=>:userId}, @active_record=User(id: integer, created_at: datetime, updated_at: datetime, name: string, username: string, email: text, phone: text, website: text), @klass=Post(id: integer, userId: integer, title: text, body: text, created_at: datetime, updated_at: datetime), @plural_name="posts", @type=nil, @foreign_type=nil, @constructable=true, @inverse_name=nil, @class_name="Post", @foreign_key=:userId, @active_record_primary_key="id", @inverse_which_updates_counter_cache=nil>,
    [1] #<ActiveRecord::Reflection::HasManyReflection:0x00007fb4a8669220 @name=:todos, @scope=nil, @options={:foreign_key=>:userId}, @active_record=User(id: integer, created_at: datetime, updated_at: datetime, name: string, username: string, email: text, phone: text, website: text), @klass=nil, @plural_name="todos", @type=nil, @foreign_type=nil, @constructable=true>,
    [2] #<ActiveRecord::Reflection::HasManyReflection:0x00007fb4a86594d8 @name=:albums, @scope=nil, @options={:foreign_key=>:userId}, @active_record=User(id: integer, created_at: datetime, updated_at: datetime, name: string, username: string, email: text, phone: text, website: text), @klass=nil, @plural_name="albums", @type=nil, @foreign_type=nil, @constructable=true>
]

# 若加上(macro = nil) 在後方當引數,就能指定要查has_one, has_many, belongs_to 的所有Reflection,如:
irb(main):023:0> User.reflect_on_all_associations(:has_many)
# 結果跟上面都一樣,略

研究到此,大概能釐清頭緒,得知CollectionProxy 涉及到的三個objects:owner、target、Reflection,分別是:

  • owner: User.first
  • target: posts
  • Reflection: 兩者關聯的資訊

而CollectionProxy 就是綜括以上的結果集啦~~

今天的研究就到這邊,謝謝~~

明天暫定繼續研究CollectionProxy 的方法,和稍微探討一下繼承自Relation 的東東:

ActiveRecord::Associations::CollectionProxy < Relation


上一篇
Day 15 - CollectionProxy 是什麼咧?(1)
下一篇
Day 17 - CollectionProxy 是什麼咧?(3)
系列文
SQL rookie 之天天魯一下30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言